package com.cheng.im.gateway.server;

import com.cheng.im.common.cocurrent.FutureTaskScheduler;
import com.cheng.im.common.codec.ProtobufDecoder;
import com.cheng.im.common.codec.ProtobufEncoder;
import com.cheng.im.common.utils.IOUtil;
import com.cheng.im.gateway.entity.ImWorker;
import com.cheng.im.gateway.handler.ChatMsgHandler;
import com.cheng.im.gateway.handler.ChatRedirectHandler;
import com.cheng.im.gateway.handler.LoginRequestHandler;
import com.cheng.im.gateway.handler.ServerExceptionHandler;
import com.cheng.im.gateway.mq.RocketMQListen;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.InetSocketAddress;

/**
 * @author Cheng
 * 连接服务器
 */
@Slf4j
@Component
public class TCPServer {

    @Value("${server.port.tcp.in}")
    private int port;

    private NioEventLoopGroup bossGroup;

    @Resource(name = "nioEventLoopGroup")
    private NioEventLoopGroup workerGroup;

    private NioServerSocketChannel serverChannel;

    @Resource
    private LoginRequestHandler loginRequestHandler;

    @Resource
    private ChatRedirectHandler chatRedirectHandler;

    @Resource
    private ServerExceptionHandler serverExceptionHandler;

    @Resource
    private ChatMsgHandler chatMsgHandler;

    @Resource
    private RocketMQListen rocketMQListen;

    @PostConstruct
    public void start() {
        log.info("=====================tcp服务器开始启动===============================");
        bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("nioBoss"));
        String ip = IOUtil.getHostAddress();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast("deCoder", new ProtobufDecoder());
                        ch.pipeline().addLast("enCoder", new ProtobufEncoder());
                        ch.pipeline().addLast("login", loginRequestHandler);
//                        ch.pipeline().addLast("chatRedirect", chatRedirectHandler);
                        ch.pipeline().addLast("chatMsgHandler", chatMsgHandler);
                        ch.pipeline().addLast("ServerExceptionHandler", serverExceptionHandler);
                    }
                })
                .localAddress(new InetSocketAddress(ip, port));

        try {
            ChannelFuture sync = serverBootstrap.bind().sync();
            sync.addListener(future -> {
                if (future.isSuccess()) {
                    log.info("端口绑定成功 ImServer start success! port:{}", port);
                } else {
                    log.info("端口绑定失败! port:{}", port);
                }
            });
            serverChannel = (NioServerSocketChannel) sync.channel();

            InetAddress address = serverChannel.localAddress().getAddress();
            log.info("address地址： {}", address);

            // 本地节点初始化
            ImWorker.getInst().setLocalNode(ip, port);

            FutureTaskScheduler.add(() ->
            {
                /**
                 * 启动节点
                 */
                ImWorker.getInst().init();
                // 初始化监听节点
                rocketMQListen.initConsumers();
                /**
                 * 启动节点的管理，已经注册为beam可以不使用这个了
                 */
                // WorkerRouter.getInst().init();
            });
            log.info("=====================tcp服务器启动结束===============================");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @PreDestroy
    private void destroy(){
        if (serverChannel != null) {
            serverChannel.close();
        }
        if(bossGroup != null && !bossGroup.isShutdown()){
            bossGroup.shutdownGracefully();
        }
        if(workerGroup != null && !workerGroup.isShutdown()){
            workerGroup.shutdownGracefully();
        }
    }
}
